# ----------------------------------------------------------------------------
#       Copyright (C) 2013-2014 Huynh Vi Lam  <domovilam@gmail.com>
#
#       This file is part of pimucha.
#
#	This program is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#	
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#	
#	You should have received a copy of the GNU General Public License
#	along with this program.  If not, see <http://www.gnu.org/licenses/>.
# ----------------------------------------------------------------------------

# ----------------------------------------------------------------------------
# Use for receive events incoming from netcontroller
# Format the incoming event for sending to next target
# Use for transmit command to controller
# ----------------------------------------------------------------------------

import logging,sys,threading,time
if sys.hexversion > 0x030000F0:
    import queue as Queue
else:
    import Queue
QEmpty = Queue.Empty
from piHAlibs import (broadcast,filterevt,unduplicate)
from .importapps import NETControllers
from .servers import (PortInUse,SetupControllers,SetupDaemons,TXControllers)

logger = logging.getLogger()


class NETCONTROLLER(object):
    def __init__(self,idcontroller,addr,RX=None):
        self.idcontroller = idcontroller
        self.name = self.idcontroller
        self.addr = addr
        self.TXcap = None
        self.stop = False
        self.opened = False
        self.setup = False
        if idcontroller in NETControllers:
            self.netcontroller = NETControllers[idcontroller](addr,RX)
        else:
            logger.critical("No netcontroller associated with %s",idcontroller)
            self.netcontroller = None
            return
        self.featurenames = []
        self.features = []
        self.decodernames = []
        self.decoders = []
        self.dfeaturenames = []
        self.dfeatures = []
        self.loccmdq = Queue.Queue()
        self.servercmds = {
            'ALLRXTX':self.allrxtx,
            'DROPDUPRX':self.dropduprx,
            'FILTEREVENT':self.filterevent,
            'NOEVENT':self.noevent,
            'STOPS':self.stops}
        if self.netcontroller.TXcap : self.TXcap = True

    def __del__(self):
        if self.setup:
            self.close()

    def close(self):
        self.netcontroller.close()

    def tsetup(self):
        if self.netcontroller:
            self.netcontroller.tsetup()
            self.opened = self.netcontroller.opened
            self.setup = self.netcontroller.setup
        if self.setup:
            self.namedev = self.name + ':' + self.idcontroller
            self.namectrl = self.name + ':' + self.idcontroller[1:]
            PortInUse.setdefault(self.addr)
            PortInUse[self.addr] = self.namedev
            SetupDaemons.setdefault(self.namedev)
            SetupDaemons[self.namedev] = self
            if self.namedev not in SetupControllers:
                SetupControllers.setdefault(self.namedev)
                SetupControllers[self.namedev] = self
                logger.debug("Added in SetupControllers %s",repr(SetupControllers))
            if (self.namedev not in TXControllers) and (self.TXcap):
                TXControllers.setdefault(self.namedev)
                TXControllers[self.namedev] =  self.netcontroller
                logger.debug("Added in TXControllers %s",repr(TXControllers))

    def cleanm(self):
        for d in self.decoders:
            d.close()
            self.decoders.remove(d)
        for d in self.decodernames:
            self.decodernames.remove(d)
        for f in self.features:
            f.close()
            self.features.remove(f)
        for f in self.featurenames:
            self.featurenames.remove(f)
        if self.namedev in TXControllers: del TXControllers[self.namedev]          
        if self.namedev in SetupControllers: del SetupControllers[self.namedev]
        if self.addr in PortInUse: del PortInUse[self.addr]
        self.netcontroller.close()

    def control(self):
        """
        Control the receive loop for receiving events
        """
        if self.netcontroller.opened == False:
            logger.debug("Device %s disconnected - Break Stop",self.name)
            self.stop = True
            self.setup = False
            self.close()

    def getnetcmdq(self):
        try:
            data = self.loccmdq.get_nowait()
        except QEmpty:
            return
        for nctrl in TXControllers:
            if isinstance(data,list) : data = ' '.join(data)
            TXControllers[nctrl].netsend(data)
            return
        else:
            logger.error("No controller detected for sending command %s", repr(data))
        return

    def dispatch(self,target):
        if not self.setup: return
        while not self.stop:
            if self.netcontroller.RXcap:
                event = None
                event = self.netcontroller.rxevent()
                if event:
                    logger.debug("Event %s send to target %s...",repr(event),target.__name__)
                    target.send([self.namectrl,event])
            # getting cmd from NETCMDq for sending to network controller TX
            self.getnetcmdq()
            # control loop
            self.control()
            time.sleep(0.1)
        self.cleanm()

    def dispcmd(self):
        if not self.setup: return
        while not self.stop:
            # getting cmd from NETCMDq for sending to network controller TX
            self.getnetcmdq()
            # control loop
            self.control()
            time.sleep(0.1)
        self.cleanm()

    def allRXTX(self):
        self.dispatch(
            target=broadcast(self.features)
            )

    def dropdupRX(self):
        self.dispatch(
            target=unduplicate(broadcast(self.features),ellapse=3)
            )

    def filterEVT(self):
        self.dispatch(
            target=filterevt(broadcast(self.features),filter='FilterEVT')
            )

    def allrxtx(self):
        self.tt = threading.Thread(target=self.allRXTX)
        self.startt()

    def dropduprx(self):
        self.tt = threading.Thread(target=self.dropdupRX)
        self.startt()

    def filterevent(self):
        self.tt = threading.Thread(target=self.filterEVENT)
        self.startt()

    def noevent(self):
        self.tt = threading.Thread(target=self.dispcmd)
        self.startt()

    def startt(self):
        self.tt.name = 'NETCONTROLLEROf_' + self.namedev
        self.tt.start()
        self.ttname = self.tt.name
        print('%s starting...' % self.tt.name)

    def stops(self):
        self.stop = True
        print('%s stopping and purge...' % self.ttname)
